﻿using MCUPackage;
using MCUPackage.Utils;
using SxPackages.STC8.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace SxPackages.STC8
{
	/// <summary>
	/// 工程文件模板工具类
	/// </summary>
	static class PrjTemplate
	{
		/// <summary>
		/// 文件选项模板, 2表示默认, 1表示选中, 提供三个设置项
		/// AlwaysBuild: 总是编译, 用于ProjectConfig.c
		/// GenerateAssemblyFile, AssembleAssemblyFile用于FreeRTOS系统的port.c文件
		/// </summary>
		private const string FILE_OPTION =
@"
              <FileOption>
                <CommonProperty>
                  <UseCPPCompiler>2</UseCPPCompiler>
                  <RVCTCodeConst>0</RVCTCodeConst>
                  <RVCTZI>0</RVCTZI>
                  <RVCTOtherData>0</RVCTOtherData>
                  <ModuleSelection>0</ModuleSelection>
                  <IncludeInBuild>2</IncludeInBuild>
                  <AlwaysBuild>{0}</AlwaysBuild>
                  <GenerateAssemblyFile>{1}</GenerateAssemblyFile>
                  <AssembleAssemblyFile>{2}</AssembleAssemblyFile>
                  <PublicsOnly>2</PublicsOnly>
                  <StopOnExitCode>11</StopOnExitCode>
                  <CustomArgument></CustomArgument>
                  <IncludeLibraryModules></IncludeLibraryModules>
                  <ComprImg>1</ComprImg>
                  <BankNo>65535</BankNo>
                </CommonProperty>
                <File51>
                  <C51>
                    <RegisterColoring>2</RegisterColoring>
                    <VariablesInOrder>2</VariablesInOrder>
                    <IntegerPromotion>2</IntegerPromotion>
                    <uAregs>2</uAregs>
                    <UseInterruptVector>2</UseInterruptVector>
                    <Fuzzy>8</Fuzzy>
                    <Optimize>10</Optimize>
                    <WarningLevel>3</WarningLevel>
                    <SizeSpeed>2</SizeSpeed>
                    <ObjectExtend>2</ObjectExtend>
                    <ACallAJmp>2</ACallAJmp>
                    <InterruptVectorAddress>0</InterruptVectorAddress>
                    <VariousControls>
                      <MiscControls></MiscControls>
                      <Define></Define>
                      <Undefine></Undefine>
                      <IncludePath></IncludePath>
                    </VariousControls>
                  </C51>
                </File51>
              </FileOption>";

		/// <summary>
		/// 文件组模板
		/// </summary>
		private const string GRP_TEMPLATE =
@"        <Group>
          <GroupName>{0}</GroupName>
          <Files>{1}
          </Files>
        </Group>";

		/// <summary>
		/// 文件模板 c文件类型为1, 头文件以及txt文件为5, 类库为4
		/// </summary>
		private const string FILE_TEMPLATE =
@"            <File>
              <FileName>{0}</FileName>
              <FileType>{1}</FileType>
              <FilePath>{2}</FilePath>{3}
            </File>";

		/// <summary>
		/// 要显示在工程中的文件集合
		/// </summary>
		private static Dictionary<PathTypes, List<string>> mFiles = new Dictionary<PathTypes, List<string>>();

		/// <summary>
		/// 初始化, 每次创建项目时都要初始化一次
		/// </summary>
		public static void Init()
		{
			mFiles.Clear();
		}

		/// <summary>
		/// 追加文件
		/// </summary>
		/// <param name="aType"></param>
		/// <param name="aFile"></param>
		public static void Append(PathTypes aType, string aFile)
		{
			if (!mFiles.ContainsKey(aType))
			{
				mFiles[aType] = new List<string>();
			}
			mFiles[aType].Add(aFile);
		}

		/// <summary>
		/// 获取指定类型的文件路径
		/// </summary>
		/// <param name="aType"></param>
		/// <param name="aPath"></param>
		/// <param name="aFile"></param>
		/// <returns></returns>
		public static string ToFilePath(this PathTypes aType, string aPath, string aFile)
		{
			return Path.Combine(aPath, aType.ToDescription(), aFile);
		}

		/// <summary>
		/// 转为STC8字典配置
		/// </summary>
		/// <param name="aOpt"></param>
		/// <param name="aLst"></param>
		/// <returns></returns>
		public static bool ToSTC8Dictionary(this GPIOOptions aOpt, Dictionary<String, List<String>> aLst)
		{
			// STC8H不支持下面两项, 强制设置为默认
			aOpt.EnableCustom = true;
			aOpt.EnableDown = false;
			return aOpt.ToDictionary(aLst);
		}

		/// <summary>
		/// 组成工程组的类型
		/// </summary>
		private static readonly PathTypes[] PRJ_TYPES = new PathTypes[]
				{ PathTypes.Inc, PathTypes.Src, PathTypes.Middlewares_ZnFat,
				 PathTypes.Drivers_STC_Src, PathTypes.Drivers_STC_Libs, PathTypes.Doc};
		/// <summary>
		/// 工程组名集合
		/// </summary>
		private static readonly string[] PRJ_GROUPS = new string[]
			{"Usr/Inc", "Usr/Src", "Middlewares/ZnFat", "Drivers/STC8", "Libs", "Doc"};

		/// <summary>
		/// 创建工程文件
		/// </summary>
		/// <param name="aPath"></param>
		public static bool Create(string aPath, STC8HUSOP20 aOptions)
		{
			if (mFiles.Count < 1)
			{
				return false;
			}

			StringBuilder grpSb = new StringBuilder();
			for (int i = 0; i < PRJ_TYPES.Length; i++)
			{
				var type = PRJ_TYPES[i];
				if (mFiles.ContainsKey(type))
				{
					// 创建分组
					var files = mFiles[type];
					StringBuilder fileSb = new StringBuilder();
					foreach (var file in files)
					{
						int fileType = 5;
						if (file.EndsWith(".c", StringComparison.CurrentCultureIgnoreCase))
						{
							fileType = 1;
						}
						if (file.EndsWith(".A51", StringComparison.CurrentCultureIgnoreCase))
						{
							fileType = 2;
						}
						else if (file.EndsWith(".lib", StringComparison.CurrentCultureIgnoreCase))
						{
							fileType = 4;
						}
						string path = string.Format("../{0}/{1}", type.ToDescription(), file);
						// 特殊配置
						string opt = string.Empty;
						if (type == PathTypes.Src && file.Equals("ProjectConfig.c", StringComparison.CurrentCultureIgnoreCase))
						{
							// 项目配置文件
							opt = string.Format(FILE_OPTION, 1, 2, 2);
						}
						fileSb.AppendLine();
						fileSb.AppendFormat(FILE_TEMPLATE, file, fileType, path, opt);
					}
					grpSb.AppendLine();
					grpSb.AppendFormat(GRP_TEMPLATE, PRJ_GROUPS[i], fileSb.ToString());
				}
			}

			string src = PathTypes.MDK.ToFilePath(aOptions.TemplatePath, "Template.uvproj");
			string dst = PathTypes.MDK.ToFilePath(aPath, $"{aOptions.Project.Name}.uvproj");
			var pairs = TemplateHelper.CreatePairs();

			pairs["ProjectName"] = aOptions.Project.Name;
			pairs["Freq"] = Convert.ToString((int)(aOptions.mSystem.FreqValue * 1000));
			pairs["Groups"] = grpSb.ToString();

			return aOptions.CreateByTemplate(src, dst, pairs);
		}
	}
}
